function test (person) {
    person.age = 0
    console.log('1', obj1 === person, obj1, person); 
    // true { name: 'b', age: 0 } { name: 'b', age: 0 }
    // 这时 obj1 和 person 都是拥有同一个对象的地址指针
    // 所以这里修改了 person.age，obj1.age 也会变化
    
    person = {
        name: 'a',
        age: 1
    }
    console.log('2', obj1 === person, obj1, person); 
    // false { name: 'b', age: 0 } { name: 'a', age: 1 }
    // person 重新赋值，拥有的是一个新对象的指针，所以和 obj1 也就不相等了

    return person
}
const obj1 = {
    name: 'b',
    age: 2
}
const obj2 = test(obj1) // obj1 传递的是地址指针副本

console.log(obj1); // { name: 'b', age: 0 }
console.log(obj2); // { name: 'a', age: 1 }

/**************************  typeof   ***************************/

typeof 1          // 'number'
typeof '1'        // 'string'
typeof undefined  // 'undefined'
typeof true       // 'boolean'
typeof Symbol()   // 'symbol'

// 除了函数外的对象都会显示 'object'
typeof []          // 'object'   
typeof {}          // 'object'
typeof console.log // 'function'
typeof null        // 'object'

/**************************  instanceof   ***************************/
const Person = function () {}
const p1 = new Person()
p1 instanceof Person   // true

const arr = new Array()
arr instanceof Array // true

const obj = new Object()
obj instanceof Object // true

const n = null
n instanceof Object // false

var str1 = 'hello'
str1 instanceof String // false

var str2 = new String('world')
str2 instanceof String // true

// instanceof 判断原始类型
class PrimitiveString {
    static [Symbol.hasInstance](x) {
        return typeof x === 'string'
    }
}
console.log('hello' instanceof PrimitiveString); // true

/**************************  转换类型   ***************************/
let a = {
    valueOf () {
        return 0
    },
    toString () {
        return '1'
    },
    [Symbol.toPrimitive] () {
        return 2
    }
}
1 + a // => 3
'1' + a // '12'
[11] + a // '112'
['11'] + a // '112'
[30] + a // '302'

{1} + a // 2
{2} + a // 2
{30} + a // 2

{} + a // 2
[] + a // '2'

true + a // 3
false + a // 2
undefined + a // NaN
null + a // 2

/**************************  四则运算符   ***************************/
1 + '1' // '11'
'1' + 1 // '11'
true + true // 2
false + true // 1
1 + [2,3] // '12,3'
null + null // 0
null + undefined // NaN
undefined + undefined // NaN

// 除了加法的运算符来说，只要其中一方是数字，那么另一方就会被转为数字
2 * '3' // 6
2 * [] // 0
2 * [1,2] // NaN
2 * {} // NaN
2 * false // 0
2 * null // 0
2 * undefined // NaN
/**************************  比较运算符   ***************************/
let a = {
    valueOf () {
        return 2
    },
    toString () {
        return '1'
    }
}
a > 1 // true
/**************************  箭头函数   ***************************/
function a () {
    return () => {
        return () => {
            console.log(this);
        }
    }
}
console.log(a()()()); // window
/**************************  bind   ***************************/
let a = {}
let fn = function () {
    console.log(this);
}
fn.bind().bind(a)
// fn.bind().bind(a) 等于
let fn2 = function fn1() {
    return function () {
        return fn.apply()
    }.apply(a)
}
fn2()

let a = {
    name: 'aa'
}
function foo () {
    console.log(this.name);
}
foo.bind(a)() // 'aa'
/**************************  let & const   ***************************/
var a = 1
let b = 2
const c = 3
console.log(window.b); // undefined
console.log(window.c); // undefined

function test () {
    console.log(a);
    let a
}
test()
/**************************  组合继承  ***************************/
function Parent (value) {
    this.val = value
}
Parent.prototype.getValue = function () {
    console.log(this.val);
}

function Child (value) {
    Parent.call(this, value)
}
Child.prototype = new Parent ()
const child = new Child(1)

Child.getValue()
// Child instanceO